package org.zjx.core;


import org.zjx.db.TransferDB;
import org.zjx.entity.Location;
import org.zjx.entity.Transfer;
import org.zjx.factory.RouteFactory;
import org.zjx.model.route.Route;

import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 路由图数据加载器
 * 职责：从数据源加载并构建完整路由图
 */
public class RouteGraphLoader {
    private final RouteFactory routeFactory;

    public RouteGraphLoader(RouteFactory routeFactory) {
        this.routeFactory = Objects.requireNonNull(routeFactory);
    }

    /**
     * 加载完整路由图（静态数据）
     */
    public RouteGraph loadStaticGraph() {
        RouteGraph graph = new RouteGraph();

        // 1. 加载基础传送点
        List<Transfer> transfers = new TransferDB().findAll();
        transfers.forEach(t -> graph.addRoute(routeFactory.createFromTransfer(t)));

        // 2. 生成同场景跑路路由
        generateRunningRoutes(graph);

        return graph;
    }

    /**
     * 生成同场景移动路由
     */
    private void generateRunningRoutes(RouteGraph graph) {
        // 1. 收集所有传送点的起点（本场景的传送起点）
        Set<Location> transferStartPoints = graph.getAllLocations().stream()
                .filter(loc -> graph.getRoutesFrom(loc).stream()
                        .anyMatch(route -> route.getType().isTransfer()))
                .collect(Collectors.toSet());

        // 2. 收集所有传送点的终点（其他场景传送过来的落脚点）
        Set<Location> transferEndPoints = graph.getAdjacencyMap().values().stream()
                .flatMap(List::stream)
                .filter(route -> route.getType().isTransfer())
                .map(Route::getEnd)
                .collect(Collectors.toSet());

        // 3. 同场景内：由终点（落脚点）作为起点，起点（传送点）作为终点，生成跑路路由
        transferEndPoints.forEach(endPoint -> {
            transferStartPoints.stream()
                    .filter(startPoint -> endPoint.sameScene(startPoint) && !endPoint.equals(startPoint))
                    .forEach(startPoint -> {
                        boolean indoor = endPoint.isRoom();
                        graph.addRoute(routeFactory.createRunningRoute(endPoint, startPoint, indoor));
                    });
        });
    }
}